package graph.editor;

import graph.editor.enhanced.EdgeModified;
import graph.editor.enhanced.VertexModified;

import java.awt.geom.RectangularShape;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * @opt nodefillcolor green
 * @opt attributes
 * @opt operations
 * @depend - - - graph.editor.DataToAutomaton
 * @depend - - - graph.editor.Vertex
 * @depend - - - automaton.Transition
 */
public class DataWriter {
	private 	List<EdgeModified> 	edges;
	private		File				xmlFile;
	
	public DataWriter(List<EdgeModified> edges, File xmlFile){
		this.edges 				= edges;
		this.xmlFile			= xmlFile;
	}
	
	public void save(){
		try{
			// Create DOM
			DocumentBuilderFactory 	factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder 		builder = factory.newDocumentBuilder();
			Document 				document = builder.newDocument();
			// Property
			document.setXmlVersion("1.0");
			document.setXmlStandalone(true);
			// Create DOM Tree
			Element root 				= document.createElement("graph");
			List<Node> transitionList 	= new ArrayList<Node>();
			for(int index = 0; index < edges.size(); index++){
				// States
				if (index == 0){
					Node node1= stateNodeWriter(document, (VertexModified) edges.get(index).v1);
					root.appendChild(node1);
				}
				Node node2 = stateNodeWriter(document, (VertexModified) edges.get(index).v2);
				
				root.appendChild(node2);

				// Transition
				Node node3 = transitionNodeWriter(document, edges.get(index), index);
				transitionList.add(node3);
			}
			
			// Append transition to root document
			for(Node node : transitionList){
				root.appendChild(node);
			}
			
			document.appendChild(root);
			
			domToXML(document, xmlFile);
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	private Node stateNodeWriter(Document document, VertexModified v){
		Element state 			= document.createElement("state");
		Element id				= document.createElement("id");
		Element vertexCenterX 	= document.createElement("positionX");
		Element vertexCenterY 	= document.createElement("positionY");
		Element isInitial 		= document.createElement("isInitial");
		Element isFinal 		= document.createElement("isFinal");
		id.setTextContent(v.label);
		vertexCenterX.setTextContent(Double.toString(v.shape.getCenterX()));
		vertexCenterY.setTextContent(Double.toString(v.shape.getCenterY()));
		isInitial.setTextContent(Boolean.toString(DataToAutomaton.getState(v).initial()));
		isFinal.setTextContent(Boolean.toString(DataToAutomaton.getState(v).terminal()));
		state.appendChild(id);
		state.appendChild(vertexCenterX);
		state.appendChild(vertexCenterY);
		state.appendChild(isInitial);
		state.appendChild(isFinal);	
		return state;
	}
	
	private Node transitionNodeWriter(Document document, EdgeModified edge, int id){
		Vertex v1 = edge.v1;
		Vertex v2 = edge.v2;
		Element transition 	= document.createElement("transition");
		Element transitionId= document.createElement("id");
		Element label 		= document.createElement("label");
		Element source 		= document.createElement("source");
		Element target 		= document.createElement("target");
		transitionId.setTextContent(Integer.toString(id));
		label.setTextContent(edges.get(id).getText());
		source.setTextContent(v1.label);
		target.setTextContent(v2.label);
		transition.appendChild(transitionId);
		transition.appendChild(label);
		transition.appendChild(source);
		transition.appendChild(target);
		
		List<RectangularShape> joinPointList = edge.getJointPoints();
		if(joinPointList.size() > 0){
			for(int index = 0; index < joinPointList.size(); index++){
				Node node =  pointNodeWriter(document, joinPointList.get(index), index);
				transition.appendChild(node);
			}
		}
		return transition;
		
	}
	private Node pointNodeWriter(Document document, RectangularShape rs, int id){
		Element point 	= document.createElement("point");
		Element pointId	= document.createElement("id");
		Element centerX = document.createElement("positionX");
		Element centerY = document.createElement("positionY");
		pointId.setTextContent(Integer.toString(id));
		centerX.setTextContent(Double.toString(rs.getCenterX()));
		centerY.setTextContent(Double.toString(rs.getCenterY()));
		point.appendChild(pointId);
		point.appendChild(centerX);
		point.appendChild(centerY);
		return point;
	}
	
	private void domToXML(Document document, File xmlFile){
		try{
			// create DOM source
			DOMSource source = new DOMSource(document);
			
			// Content File
			 StringWriter stringWriter = new StringWriter();
				
			// Create output file
			Result resultat = new StreamResult(stringWriter);
			
			// Configure
			TransformerFactory 	factory		= TransformerFactory.newInstance();
			factory.setAttribute("indent-number", new Integer(4));
			Transformer 		transformer = factory.newTransformer();
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			
			// Transform
			transformer.transform(source, resultat);
			
			String xmlString = stringWriter.toString();
			FileWriter fileWriter = new FileWriter(xmlFile.getAbsolutePath(), false);
			BufferedWriter output = new BufferedWriter(fileWriter);
			try{
				output.write(xmlString);
				output.flush();
			}catch(IOException e){
				e.printStackTrace();
			}finally{
				output.close();
			}
			
		}catch (TransformerConfigurationException e) {
			e.printStackTrace();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

}
